package com.zst.common.buffer;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * 一个在指定范围内循环自增取值整数值，线程安全
 */
public class AtomicRangeInteger {
    private static final int OFFSET = 15;
    private AtomicIntegerArray array;

    private int startValue;
    private int endValue;

    public  AtomicRangeInteger(int startValue, int maxValue) {
        // 控制AtomicIntegerArray的内存大小为cacheLine size的整数倍，以便解决false sharing提高缓存命中率
        // 这里选择31，应该是为了吧int数组的内存大小控制位128Bytes（31 * 4 + 其他java对象头的大小），因为不同硬件的
        // cacheLine size不一定一样，但是肯定是8Byte的整数倍（在64位机器上），所以控制好这个数字差不多就行
        this.array = new AtomicIntegerArray(31);
        // offset的值其实问题不会很大，选一个中间的值，控制同一个cacheLine内的数据不会被其他代码修改即可
        this.array.set(OFFSET, startValue);
        this.startValue = startValue;
        this.endValue = maxValue - 1;
    }

    /**
     * @return
     */
    public int next() {
        int next;
        do {
            next = array.incrementAndGet(OFFSET);
            if (next > endValue && array.compareAndSet(OFFSET, next, startValue)) {
                // 超过endValue然后由cas成功的只会有一个线程，进入此分支后返回endValue，就实现了控制并发时返回的值都在endValue内
                return endValue;
            }
        } while (next > endValue);
        return next - 1;
    }
}
